package com.library.guard.core.service;

import ZO_API.NO1_Api;
import com.alibaba.fastjson2.JSON;
import com.library.books.domain.DoorAlarmRecord;
import com.library.books.domain.vo.BooksJoinBooksCopy;
import com.library.books.mapper.BooksCopyMapper;
import com.library.books.service.IDoorAlarmRecordService;
import com.library.common.constant.SysConfigConstants;
import com.library.common.core.redis.RedisCache;
import com.library.common.enums.BooksCopyStatus;
import com.library.common.enums.OperateTerraceType;
import com.library.common.utils.StringUtils;
import com.library.common.wspoint.client.GlobalServerPointClient;
import com.library.framework.manager.AsyncManager;
import com.library.common.wspoint.point.GlobalServerPoint;
import com.library.guard.core.ZeroAndOneApi;
import com.library.guard.core.config.N01Config;
import com.library.guard.core.domain.*;
import com.library.system.service.impl.SysConfigServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.script.RedisScript;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @Package: com.library.guard.core
 * @ClassName: Connect
 * @Author: Yin
 * @Date: 11:30
 * @Description: 连接
 */
@Slf4j
@Component
public class ZeroAndOneService {

    @Resource
    private BooksCopyMapper booksCopyMapper;

    @Resource
    private IDoorAlarmRecordService doorAlarmRecordService;

    @Resource
    SysConfigServiceImpl sysConfigService;

    @Resource
    RedisCache redisCache;

    @Resource
    GlobalServerPoint globalServerPoint;

    @Resource
    GlobalServerPointClient globalServerPointClient;

    /** 两台设备 */
    private static final ConcurrentHashMap<String,ZeroAndOneApi> currentDevice = new ConcurrentHashMap<>();

    /** 操作：2025-01-22
     *  已分离出去，系统的内容存在云端，设备的代码存在本地
     */
    /// 2024-12 注释之前的
//    @PostConstruct
    public void initDevice() {
        // 初始连接设备，设备ip来自系统参数
        String ips = sysConfigService.selectConfigByKey(SysConfigConstants.DOOR_DRIVE_IPS);
        if(ips ==null || ips.isEmpty()) {
            log.error("智能门禁初始连接ip:[{}]失败",ips);
            return;
        }
        String[] split = ips.split(",");
        for (String ip : split) {
            // 创建调用对象
            ZeroAndOneApi zeroAndOneApi = new ZeroAndOneApi(ip);
            currentDevice.put(ip,zeroAndOneApi);
            // 服务启动，但是设备未启动时。尝试连接
            AsyncManager.me().execute(new TimerTask() {
                @Override
                public void run() {
                    try {
                        TimeUnit.SECONDS.sleep(5);
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                    // 从缓存中获取数据检查
                    zeroAndOneApi.setTagCacheReadCheckCallback(() -> {
                        try{
                            // 从缓存中读取设备回调存进去的数据进行处理检查
                            List setTags = (List) redisCache.redisTemplate.execute(RedisScript.of(N01Config.TAG_PULL_HASH_SCRIPT, List.class), List.of(zeroAndOneApi.getCallbackTagCacheKey()));
                            // log.info("从缓存中获取数据检查：{}",setTags);
                            if(setTags != null && setTags.size() > 0) {
                                List<DeviceReportData.Epc> simpleEpcs = new ArrayList<>();
                                for (Object setTag : setTags) {
                                    try {
                                        DeviceReportData.Epc epc = (DeviceReportData.Epc)setTag;
                                        epc.setIp(ip);
                                        simpleEpcs.add(epc);
                                    }catch (Exception e) {
                                        log.error("设备[{}]未从缓存[{}]中检查到的数据，或许不是一个EPC对象",ip,setTag);
                                    }
                                }
                                if(! simpleEpcs.isEmpty()) {
                                    // 创建一个检查数据
                                    DeviceReportData deviceReportData = new DeviceReportData();
                                    deviceReportData.setEpcs(simpleEpcs);
                                    deviceReportData.setTagCount(setTags.size());
                                    deviceReportData.setIp(ip);

                                    DeviceReport deviceReport = new DeviceReport();
                                    deviceReport.setData(deviceReportData);
                                    deviceReport.setCmd("20001");
                                    deviceReport.setIp(ip);

                                    // 检查
                                    checkBooks(deviceReport);
                                }else{
                                    log.error("设备[{}]未从缓存[{}]中检查到可用数据",ip,setTags);
                                }
                            }
                        } catch (Exception e) {
                            throw new RuntimeException(e);
                        }
                    });

                    // 快速盘存回调
                    zeroAndOneApi.setAsyncReadingCallback(tagBackData -> {
                        try{
                            Thread.sleep(100);
                        }catch (Exception e){
                            log.error("快速盘存回调读取失败失败[超时异常]");
                            e.printStackTrace();
                        }
                        // 检查缓存中是否存在（手动处理重复标签）
                        String bankData = tagBackData.getBank_data();
                        if(bankData == null) {
                            return;
                        }

                        log.info("设备[{}]读取到RFID：{},ANT：{}",zeroAndOneApi.getIp(),bankData,tagBackData.getAntid());

                        // 不存在时 Set
                        if(redisCache.hasKey(N01Config.DOOR_REDO_CACHE_KEY + bankData)) {
                            log.info("重复标签：{}",bankData);
                            return;
                        }
                        // 重复标签过期时间
                        redisCache.setCacheObject(N01Config.DOOR_REDO_CACHE_KEY + bankData,"1");
                        redisCache.expire(N01Config.DOOR_REDO_CACHE_KEY + bankData,N01Config.DOOR_REDO_CACHE_KEY_TIMEOUT,TimeUnit.SECONDS);
                        log.info("不重复标签：{}",bankData);

                        DeviceReportData.Epc epc = new DeviceReportData.Epc();
                        epc.setEpc(tagBackData.getEpc());
                        epc.setBankData(bankData);
                        epc.setAnt(tagBackData.getAntid());
                        epc.setRssi(tagBackData.getRssi());
                        epc.setReadCount(tagBackData.getCounts());

                        // 手动推入缓存中
//                        redisCache.redisTemplate.opsForSet().add(zeroAndOneApi.getCallbackTagCacheKey(),epc);
//                        redisCache.redisTemplate.opsForSet().add(zeroAndOneApi.getCallbackTagCacheKey(),bankData);
                        redisCache.redisTemplate.opsForHash().put(zeroAndOneApi.getCallbackTagCacheKey(),bankData,epc);
                    });
                    // 开启盘存
                    log.info("智能门禁快速盘存初始开启：{}", zeroAndOneApi.startAsyncReading());
                }
            });
        }
    }

    @PreDestroy
    public void destroy() {
        currentDevice.forEach((key,val) -> {
            val.disconnect();
            log.info("系统退出 智能门禁设备[{}]关闭连接",val.getIp());
        });
    }

    /// 2024-12 注释之后的（移除了一些多余）
//    @PostConstruct
//    public void initDevice() {
//        // 初始连接设备，设备ip来自系统参数
//        String ips = sysConfigService.selectConfigByKey(N01Config.SYS_CONFIG);
//        if(ips ==null || ips.isEmpty()) {
//            log.error("智能门禁初始连接ip:[{}]失败",ips);
//            return;
//        }
//        String[] split = ips.split(",");
//        for (String ip : split) {
//            // 创建调用对象，但是设备可能未启动。尝试重连
//            ZeroAndOneApi zeroAndOneApi = new ZeroAndOneApi(ip);
//            currentDevice.put(ip,zeroAndOneApi);
//        }
//    }

    /**
     * set gpo
     * @param gpoSet
     * @return
     */
    public boolean setGpo(GpoSet gpoSet) {
        ZeroAndOneApi zeroAndOneApi = currentDevice.get(gpoSet.getIp());
        if(zeroAndOneApi == null) {
            throw new RuntimeException("ip[" + gpoSet.getIp() + "]未连接");
        }
        return zeroAndOneApi.setGpo(gpoSet);
    }

    /**
     * set 天线功率
     * @param antSet 天线
     */
    public boolean setAnt(AntSet antSet) {
        ZeroAndOneApi zeroAndOneApi = currentDevice.get(antSet.getIp());
        if(zeroAndOneApi == null) {
            throw new RuntimeException("ip[" + antSet.getIp() + "]未连接");
        }
        return zeroAndOneApi.setAntPower(antSet);
    }

    /// 2024-12 注释之后
    /*public void checkBooksTow(DeviceReport deviceReport) {
        ZeroAndOneApi zeroAndOneApi = currentDevice.get(deviceReport.getIp());
        zeroAndOneApi.checks(deviceReport);
    }*/

    /// 2024-12 注释之前
    public void checkBooks(DeviceReport deviceReport) {
        ZeroAndOneApi zeroAndOneApi = currentDevice.get(deviceReport.getIp());
        if(zeroAndOneApi != null) {
//        if(zeroAndOneApi == null) {
            DeviceReportData data = deviceReport.getData();
            // 以bank_data 为准
            List<DeviceReportData.Epc> epcs = data.getEpcs();

            if (StringUtils.isNotEmpty(epcs)) {
                // 以key为准 (可重复使用)
                Map<String, List<DeviceReportData.Epc>> epcMaps = epcs.stream()
                        .filter(Objects::nonNull)
                        .collect(Collectors.groupingBy(DeviceReportData.Epc::getBankData));

                AsyncManager.me().execute(new TimerTask() {
                    @Override
                    public void run() {
                        try {
                            Set<String> epsStrList = epcMaps.keySet();
                            log.info("异步处理设备[{}]读到标签数:{}", zeroAndOneApi.getIp() ,epsStrList.size());

                            // 书籍拼接副本数据(软删除)
                            List<BooksJoinBooksCopy> booksCopies = booksCopyMapper.selectBooksCopyJoinBooksList(new BooksJoinBooksCopy().setQueryRfids(epsStrList));
                            if (! booksCopies.isEmpty()) {
                                // 红（已录入未借出）
                                List<BooksJoinBooksCopy> isScanNormal = booksCopies.stream()
                                        .filter(b -> BooksCopyStatus.NORMAL.equals(b.getBooksCopyStatus()))
                                        .collect(Collectors.toList());
                                // 绿
                                boolean isScanLend = booksCopies.stream().anyMatch(b -> BooksCopyStatus.LEND.equals(b.getBooksCopyStatus()));
                                // 有未借出数据
                                log.info("未借:{},已借:{}", !isScanNormal.isEmpty(),isScanLend);
                                if (!isScanNormal.isEmpty()) {
                                    log.info("GPO 1");
                                    zeroAndOneApi.setGpo(GpoSet.red() , ()-> {
                                        AsyncManager.me().execute(new TimerTask() {
                                            @Override
                                            public void run() {
                                                // 批量添加报警记录数据
                                                List<DoorAlarmRecord> alarmRecord = isScanNormal.stream()
                                                        .map(scanNormal -> {
                                                            DeviceReportData.Epc alarmEpc = epcMaps.get(scanNormal.getBooksCopyRfid()).get(0);
                                                            return new DoorAlarmRecord()
                                                                    .setAlarmIp(alarmEpc.getIp())
                                                                    .setAlarmAnt(alarmEpc.getAnt())
                                                                    .setAlarmBankData(alarmEpc.getBankData())
                                                                    .setBooksId(scanNormal.getBooksId())
                                                                    .setBooksIsbn(scanNormal.getBooksIsbn())
                                                                    .setBooksName(scanNormal.getBooksName())
                                                                    .setBooksCoverPhoto(scanNormal.getBooksCoverPhoto())
                                                                    .setBooksCopyLicense(scanNormal.getBooksCopyLicense())
                                                                    .setOperateTerrace(OperateTerraceType.DESK.getCode());
                                                        }).collect(Collectors.toList());
                                                doorAlarmRecordService.saveBatch(alarmRecord);
                                                // 发送报警给系统
                                                AlarmWsData alarmWsData = new AlarmWsData();
                                                alarmWsData.setList(alarmRecord);
                                                globalServerPoint.send(alarmWsData);
                                            }
                                        });
                                    });
                                    // 持续时间
                                    Thread.sleep(1000);
                                    zeroAndOneApi.setGpo(GpoSet.def());
                                    log.info("GPO 2");
                                }else if(! zeroAndOneApi.isShow("1")) {
                                    // 同步
                                    if (zeroAndOneApi.ONE_LOCK.tryLock(500, TimeUnit.MILLISECONDS)) {
                                        try {
                                            zeroAndOneApi.sets.addAll(epsStrList);
                                            log.info("tags size:{}", zeroAndOneApi.sets.size());

                                            if (isScanLend) {
                                                zeroAndOneApi.setGpo(GpoSet.green());
                                                Thread.sleep(1000);
                                                if(zeroAndOneApi.isShow("2")) {
                                                    zeroAndOneApi.setGpo(GpoSet.def());
                                                }
                                            }
                                        }finally {
                                            zeroAndOneApi.ONE_LOCK.unlock();
                                        }
                                    }
                                }
                            }else {
                                log.info("非数据库RFID数据");
                            }
                        }catch (Exception e) {
                            log.error("扫描到未借书籍");
                        }
                    }
                });
            }
        }
    }

    public void checkBooksLocalTest(DeviceReport deviceReport) {
        DeviceReportData data = deviceReport.getData();
        // 以bank_data 为准
        List<DeviceReportData.Epc> epcs = data.getEpcs();

        if (StringUtils.isNotEmpty(epcs)) {
            // 以key为准 (可重复使用)
            Map<String, List<DeviceReportData.Epc>> epcMaps = epcs.stream()
                    .filter(Objects::nonNull)
                    .collect(Collectors.groupingBy(DeviceReportData.Epc::getBankData));

            AsyncManager.me().execute(new TimerTask() {
                @Override
                public void run() {
                    try {
                        Set<String> epsStrList = epcMaps.keySet();
                        log.info("异步处理设备[{}]读到标签数:{}", "127.0.0.1" ,epsStrList.size());

                        // 书籍拼接副本数据(软删除)
                        List<BooksJoinBooksCopy> booksCopies = booksCopyMapper.selectBooksCopyJoinBooksList(new BooksJoinBooksCopy().setQueryRfids(epsStrList));
                        if (! booksCopies.isEmpty()) {
                            // 红（已录入未借出）
                            List<BooksJoinBooksCopy> isScanNormal = booksCopies.stream()
                                .filter(b -> BooksCopyStatus.NORMAL.equals(b.getBooksCopyStatus()))
                                .collect(Collectors.toList());
                            // 绿
                            boolean isScanLend = booksCopies.stream().anyMatch(b -> BooksCopyStatus.LEND.equals(b.getBooksCopyStatus()));
                            // 有未借出数据
                            log.info("未借:{},已借:{}", !isScanNormal.isEmpty(),isScanLend);
                            if (!isScanNormal.isEmpty()) {
                                log.info("GPO 1");
                                AsyncManager.me().execute(new TimerTask() {
                                    @Override
                                    public void run() {
                                        // 批量添加报警记录数据
                                        List<DoorAlarmRecord> alarmRecord = isScanNormal.stream()
                                            .map(scanNormal -> {
                                                DeviceReportData.Epc alarmEpc = epcMaps.get(scanNormal.getBooksCopyRfid()).get(0);
                                                return new DoorAlarmRecord()
                                                    .setAlarmIp(alarmEpc.getIp())
                                                    .setAlarmAnt(alarmEpc.getAnt())
                                                    .setAlarmBankData(alarmEpc.getBankData())
                                                    .setBooksId(scanNormal.getBooksId())
                                                    .setBooksIsbn(scanNormal.getBooksIsbn())
                                                    .setBooksName(scanNormal.getBooksName())
                                                    .setBooksCoverPhoto(scanNormal.getBooksCoverPhoto())
                                                    .setBooksCopyLicense(scanNormal.getBooksCopyLicense())
                                                    .setBarcode(scanNormal.getBooksCopyBarcode())
                                                    .setOperateTerrace(OperateTerraceType.DESK.getCode());
                                            }).collect(Collectors.toList());
                                        doorAlarmRecordService.saveBatch(alarmRecord);
                                        // 发送报警给系统
                                        AlarmWsData alarmWsData = new AlarmWsData();
                                        alarmWsData.setList(alarmRecord);
                                        // globalServerPoint.send(alarmWsData);
                                        globalServerPointClient.send(alarmWsData);
                                    }
                                });
                                // 持续时间
                                Thread.sleep(1000);
                                log.info("GPO 2");
                            }
                        }else {
                            log.info("非数据库RFID数据");
                        }
                    }catch (Exception e) {
                        log.error("扫描到未借书籍");
                    }
                }
            });
        }
    }

    public void led(String ip, String led) {
        ZeroAndOneApi zeroAndOneApi = currentDevice.get(ip);
        if("1".equals(led)) {
            zeroAndOneApi.setGpo(GpoSet.green());
        }else if("2".equals(led)) {
            zeroAndOneApi.setGpo(GpoSet.red());
        } else{
            zeroAndOneApi.setGpo(GpoSet.def());
        }
    }

    /** 模拟读卡器启动 */
    public void demo() {

        String cacheKey = N01Config.DOOR_CALLBACK_TAG_SET_CACHE_KEY + "127.0.0.1";
        AsyncManager.me().execute(new TimerTask() {
            @Override
            public void run() {
                // 从缓存中获取数据检查
                try {
                    while(true) {
                        Thread.sleep(500);
                        List setTags = (List) redisCache.redisTemplate.execute(RedisScript.of(N01Config.TAG_PULL_HASH_SCRIPT, List.class), List.of(cacheKey));

                        if (setTags != null && setTags.size() > 0) {
                            List<DeviceReportData.Epc> simpleEpcs = new ArrayList<>();
                            for (Object setTag : setTags) {
                                try {
                                    DeviceReportData.Epc epc = (DeviceReportData.Epc) setTag;
                                    epc.setIp("127.0.0.1");
                                    simpleEpcs.add(epc);
                                } catch (Exception e) { }
                            }

                            // 创建一个检查数据
                            DeviceReportData deviceReportData = new DeviceReportData();
                            deviceReportData.setEpcs(simpleEpcs);
                            deviceReportData.setTagCount(setTags.size());
                            deviceReportData.setIp("127.0.0.1");

                            DeviceReport deviceReport = new DeviceReport();
                            deviceReport.setData(deviceReportData);
                            deviceReport.setCmd("20001");
                            deviceReport.setIp("127.0.0.1");

                            // 检查
                            checkBooks(deviceReport);
                            // checkBooksTow(deviceReport);
                        }
                    }
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            }
        });

        AsyncManager.me().execute(new TimerTask() {
            @Override
            public void run() {
                List<String> rfids = List.of("E28278022000000008C901EE","E28278020000000008C900F7","E28278020000000008C90016","E28278020000000008C90015");
//                List<String> rfids = List.of();

                while(true) {
                    try {
                        Thread.sleep(10000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    // 检查缓存中是否存在（手动处理重复标签）
                    for (String bankData : rfids) {

                        // 不存在时 Set
                        if(redisCache.hasKey(N01Config.DOOR_REDO_CACHE_KEY + bankData)) {
                            log.info("重复标签：{}",bankData);
                            return;
                        }
//                        // 重复标签过期时间
//                        redisCache.setCacheObject(N01Config.DOOR_REDO_CACHE_KEY + bankData,"1");
//                        redisCache.expire(N01Config.DOOR_REDO_CACHE_KEY + bankData,N01Config.DOOR_REDO_CACHE_KEY_TIMEOUT,TimeUnit.SECONDS);

//                        redisCache.redisTemplate.opsForValue().set(N01Config.DOOR_REDO_CACHE_KEY + bankData,"1",3L,TimeUnit.SECONDS);
//                        log.info("不重复标签：{}",bankData);

                        DeviceReportData.Epc epc = new DeviceReportData.Epc();
                        epc.setEpc(bankData);
                        epc.setBankData(bankData);
                        epc.setAnt(1);
                        epc.setRssi(1);
                        epc.setReadCount(1);

                        // 手动推入缓存中
                        redisCache.redisTemplate.opsForHash().put(cacheKey,bankData,epc);
                    }
                }
            }
        });
    }

}
